package enembleClassifier;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

import mlp.Mlp;
import digitRecognitionProblem.DigitRecognitionMlpFitness;

public class EnsembleClassifier {

	enum ArgNums {
		MLPS_DIR, TEST_FIILE
	}
	
	private static String MLPS_DIR = "9_5_raw";
//	private static String MLPS_DIR = "new_func_ensemble_28_4"; // path to directory with a network for each digit
//	private static String MLPS_DIR = "/home/ofri/Desktop/new_classifier/EPOCHS_30"; // path to directory with a network for each digit
//	private static String MLPS_DIR = "/home/ofri/Desktop/MLPs/29_4_new_func_starts"; // "/home/ofri/Desktop/MLPs/new_func_ensemble_struct_rate";

	private static String TEST_FILE = "validate2_reduce.csv"; // path to test data
	
	private List<Mlp> mlps; // i'th network recognizes digit i (0 <= i <= 9)
	
	public EnsembleClassifier(String networksFile) throws ClassNotFoundException, IOException {
		
		// parse network for each digit
		mlps = readMlps(networksFile);
	} 
	
	public EnsembleClassifier(List<Mlp> mlps) {
		this.mlps = mlps;
	}
	
	private static List<Mlp> readMlps(String mlpsDirectory) throws IOException, ClassNotFoundException {

		// initialize return value
		List<Mlp> mlpsList = new LinkedList<Mlp>();
		
		// read network for each digit
		for (int digit = 0 ; digit < 10 ; ++digit) {
			
			// read network for current digit
//			FileInputStream readFile = new FileInputStream(mlpsDirectory + "/"
//					+ digit + "/mlp_0_rec_" + digit + ".txt");
//			FileInputStream readFile = new FileInputStream(mlpsDirectory + "/28_4_best_start_mlp_0_rec_" + digit + ".txt");
//			FileInputStream readFile = new FileInputStream(mlpsDirectory + "/30_EPOCHS_4_5_mlp_0_rec_" + digit + ".txt");
			FileInputStream readFile = new FileInputStream(mlpsDirectory + "/9_5_mlp_0_rec_" + digit + ".txt");
			ObjectInputStream fileStream = new ObjectInputStream(readFile);
			
			// add to networks
			mlpsList.add((Mlp)fileStream.readObject());		
			fileStream.close();
		}
		
//		// initialize return value
//		List<Mlp> mlpsList = new LinkedList<Mlp>();
//		File directory = new File(mlpsDirectory);
//		// parse neural network out of each location in input file
//		for(File file : directory.listFiles()) {
//			
////			System.out.println(file.getName());
//			// parse current neural network
//			FileInputStream readFile = new FileInputStream(file);
//			ObjectInputStream fileStream = new ObjectInputStream(readFile);
//			
//			// add to networks
//			mlpsList.add((Mlp)fileStream.readObject());		
//			fileStream.close();
//		}
//		System.out.println("reading mlps completed."); // TODO DEBUG PRINT!!!
		
		// return parsed networks
		return mlpsList;
	}
	
	public void setMlps(List<Mlp> mlps) {
		this.mlps = mlps;
	}
	
	public List<Mlp> getMlps() {
		return mlps;
	}
	
	public static void main(String[] args) {
		
//		// redirect output to file
//		try {
//			File file = new File("Details.txt");
//			FileOutputStream fos;
//			fos = new FileOutputStream(file);
//			PrintStream ps = new PrintStream(fos);
//			System.setOut(ps);
//			System.setErr(ps);
//		} catch (FileNotFoundException e1) {
//			e1.printStackTrace();
//		}
//		NETWORKS_FILE = args[ArgNums.NETWORKS.ordinal()];
//		TEST_FILE = args[ArgNums.TEST_FIILE.ordinal()];
		
		// create a new classifier
		execute();
	}

	public static void execute() {
		EnsembleClassifier classifier = null;
		try {
			classifier = new EnsembleClassifier(MLPS_DIR);
		} catch (ClassNotFoundException e) {
			// error- cannot run
			e.printStackTrace();
			return;
		} catch (IOException e) {
			// error- cannot run
			e.printStackTrace();
			return;
		}
		
		// initialize test data
		DigitRecognitionMlpFitness.initTestData(TEST_FILE);
		
		// classify test samples
		DigitRecognitionMlpFitness funcFit = new DigitRecognitionMlpFitness(classifier.mlps);
		System.out.println("Success rate on test set: "+ funcFit.getFitness(null));
	}
}
